#ifndef _TERMIOS_H
#define _TERMIOS_H

#define TTY_BUF_SIZE 1024   // tty中的缓冲区长度
// 0x54 只是一个魔数 目的是为了使这些常数唯一
/* 0x54 is just a magic number to make these relatively uniqe ('T') */
// tty设备的ioctl调用命令集 ioctl将命令编码在低位子中 名称TC【*】是指tty控制命令
#define TCGETS		0x5401  // 取相应终端termios结构中的信息（参见 tcgetattr（））
#define TCSETS		0x5402  // 设置相应终端termios结构中的信息
#define TCSETSW		0x5403  // 在设置终端termios的信息之前 需要先等待输出队列中所有数据处理完（耗尽） 对于修改参数会影响输出的情况 就需要使用这种形式
#define TCSETSF		0x5404  // 在设置termios的信息之前 需要先等待输出队列中所有数据处理完 并且刷新（清空）输入队列 再设置
#define TCGETA		0x5405  // 取相应终端termio结构中的信息
#define TCSETA		0x5406  // 设置相应终端ternio结构中的信息
#define TCSETAW		0x5407  // 在设置终端termio的信息之前 需要先等待输出队列中所有数据处理完（耗尽） 对于修改参数会影响输出的情况 就需要使用这种形式
#define TCSETAF		0x5408  // 在设置termio的信息之前 需要先等待输出队列中所有数据处理完 并且刷新（清空）输入队列 再设置
#define TCSBRK		0x5409  // 等待输出队列处理完毕 如果参数值是0 则返送一个break
#define TCXONC		0x540A  // 开始/停止控制 如果参数值是0 则挂起输出 如果是1 则重新开启挂起的输出 如果是2 则挂起输入 如果是3 则重新开启挂起的输入
#define TCFLSH		0x540B  // 刷新已写输出但还没发送或已收但还没有读数据 如果参数是0 则刷新（清空）输入队列 如果是1 则刷新输出队列 如果是2 则刷新输入和输出队列
#define TIOCEXCL	0x540C  // TIOC的含义是tty输入输出控制命令  设置中断串行线路专用模式
#define TIOCNXCL	0x540D  // 复位终端串行线路专用模式
#define TIOCSCTTY	0x540E  // 设置tty为控制终端
#define TIOCGPGRP	0x540F  // 读取指定中断设备进程的组id
#define TIOCSPGRP	0x5410  // 设置指定中断设备进程的组id
#define TIOCOUTQ	0x5411  // 返回输出队列中还未送出的字符数
#define TIOCSTI		0x5412  // 模拟终端输入 该命令以一个纸箱字符的设置所谓参数
#define TIOCGWINSZ	0x5413  // 读取终端设备窗口大小信息
#define TIOCSWINSZ	0x5414  // 设置终端设备窗口大小信息
#define TIOCMGET	0x5415  // 返回modem状态控制引线的当前状态比特位标志集
#define TIOCMBIS	0x5416  // 设置单个modem状态控制引线的状态
#define TIOCMBIC	0x5417  // 复位单个modem状态控制引线的状态
#define TIOCMSET	0x5418  // 设置modem状态引线的状态 如果某一比特位置位 则modem对应的状态线将置为有效
#define TIOCGSOFTCAR	0x5419  // 读取软件载波检测标志（1-开启 2-关闭） 对于本地连接的终端或其他设备 软件载波标志是开启的 对于使用modem线路的终端或设备则是关闭的 为了能使用这两个ioctl调用 tty线路 应该是以o_ndelay方式打开的 这样open（）就不会等待载波
#define TIOCSSOFTCAR	0x541A  // 设置软件载波检测标志（1-开启 2-关闭）
#define TIOCINQ		0x541B  // 返回输入队列中还未取走字符的数目
// 窗口大小（Window size） 属性结构 在窗口环境中可用于基于屏幕的应用程序 ioctls中的TIOCGWINSZ和TIOCSWINSZ可用来读取或设置这些信息
struct winsize {
	unsigned short ws_row;      // 窗口字符行数
	unsigned short ws_col;      // 窗口字符列数
	unsigned short ws_xpixel;   // 窗口宽度 像素值
	unsigned short ws_ypixel;   // 窗口高度 像素值
};
// AT&T系统V的termio结构
#define NCC 8   // termio结构中控制字符数组的长度
struct termio {
	unsigned short c_iflag;		/* input mode flags */      // 输入模式标志
	unsigned short c_oflag;		/* output mode flags */     // 输出模式标志
	unsigned short c_cflag;		/* control mode flags */    // 控制模式标志
	unsigned short c_lflag;		/* local mode flags */      // 本地模式标志
	unsigned char c_line;		/* line discipline */       // 线路规程（速率）
	unsigned char c_cc[NCC];	/* control characters */    // 控制字符数组
};
// POSIX的termios结构
#define NCCS 17 // termios结构中控制字符数组的长度
struct termios {
	unsigned long c_iflag;		/* input mode flags */      // 输入模式标志
	unsigned long c_oflag;		/* output mode flags */     // 输出模式标志
	unsigned long c_cflag;		/* control mode flags */    // 控制模式标志
	unsigned long c_lflag;		/* local mode flags */      // 本地模式标志
	unsigned char c_line;		/* line discipline */       // 线路规程（速率）
	unsigned char c_cc[NCCS];	/* control characters */    // 控制字符数组
};

/* c_cc characters */   // 以下是c_cc数组对应字符的索引值
#define VINTR 0         // 中断字符
#define VQUIT 1         // 退出字符
#define VERASE 2        // 擦出字符
#define VKILL 3         // 终止字符
#define VEOF 4          // 文件结束字符
#define VTIME 5         // 定时器值
#define VMIN 6          // 定时器值
#define VSWTC 7         // 交换字符
#define VSTART 8        // 开始字符
#define VSTOP 9         // 停止字符
#define VSUSP 10        // 挂起字符
#define VEOL 11         // 行结束字符
#define VREPRINT 12     // 重显示字符
#define VDISCARD 13     // 丢弃字符
#define VWERASE 14      // 单词擦除字符
#define VLNEXT 15       // 下一行字符
#define VEOL2 16        // 行结束字符

/* c_iflag bits */  // termios结构输入模式字段c_iflag各种标志的符号常熟
#define IGNBRK	0000001 // 输入时忽略BREAK条件
#define BRKINT	0000002 // 在BREAK时产生SIGINT信号
#define IGNPAR	0000004 // 忽略奇偶校验出错的字符
#define PARMRK	0000010 // 标记奇偶校验错
#define INPCK	0000020 // 允许输入奇偶校验
#define ISTRIP	0000040 // 屏蔽字符第8位
#define INLCR	0000100 // 输入时将换行符NL映射成回车符CR
#define IGNCR	0000200 // 忽略回车符CR
#define ICRNL	0000400 // 在输入时将回车符CR映射成换行符NL
#define IUCLC	0001000 // 在输入时将大写字符转换成小写字符
#define IXON	0002000 // 允许开始/停止 输出控制
#define IXANY	0004000 // 允许任何字符重启输出
#define IXOFF	0010000 // 允许开始/停止输入控制
#define IMAXBEL	0020000 // 输入队列满时响铃

/* c_oflag bits */  // termios结构中输出模式字段 c_oflag 各种标志的符号常数
#define OPOST	0000001 // 执行输出处理
#define OLCUC	0000002 // 在输出时将小写字符转换成大小字符
#define ONLCR	0000004 // 在输出时将换行符NL映射成回车-换行符CR-NL
#define OCRNL	0000010 // 在输出时将回车符CR映射成换行符NL
#define ONOCR	0000020 // 在0列不输出回车符CR
#define ONLRET	0000040 // 换行符NL执行回车符的功能
#define OFILL	0000100 // 延迟时使用条虫字符而不使用时间延迟
#define OFDEL	0000200 // 填充字符是ASCII码DEL 如果未设置 则使用ASCII NULL
#define NLDLY	0000400 // 选择换行延迟
#define   NL0	0000000 // 换行延迟类型0
#define   NL1	0000400 // 换行延迟类型1
#define CRDLY	0003000 // 选择回车延迟
#define   CR0	0000000 // 回车延迟类型0
#define   CR1	0001000 // 回车延迟类型1
#define   CR2	0002000 // 回车延迟类型2
#define   CR3	0003000 // 回车延迟类型3
#define TABDLY	0014000 // 选择水平制表延迟
#define   TAB0	0000000 // 水平制表延迟类型0
#define   TAB1	0004000 // 水平制表延迟类型1
#define   TAB2	0010000 // 水平制表延迟类型2
#define   TAB3	0014000 // 水平制表延迟类型3
#define   XTABS	0014000 // 将制表符TAB换成空格 该值标志空格数
#define BSDLY	0020000 // 选择退格延迟
#define   BS0	0000000 // 退格延迟类型0
#define   BS1	0020000 // 退格延迟类型1
#define VTDLY	0040000 // 纵向制表延迟
#define   VT0	0000000 // 纵向制表延迟类型0
#define   VT1	0040000 // 纵向制表延迟类型1
#define FFDLY	0040000 // 选择换页延迟
#define   FF0	0000000 // 换页延迟类型0
#define   FF1	0040000 // 换页延迟类型1

/* c_cflag bit meaning */   // termios 结构中控制模式标志字段c_cflag标志的符号常熟（8进制）
#define CBAUD	0000017     // 传输速率位屏蔽码
#define  B0	0000000		/* hang up */   // 挂断线路
#define  B50	0000001     // 波特率50
#define  B75	0000002     // 波特率75
#define  B110	0000003     // 波特率110
#define  B134	0000004     // 波特率134
#define  B150	0000005     // 波特率150
#define  B200	0000006     // 波特率200
#define  B300	0000007     // 波特率300
#define  B600	0000010     // 波特率600
#define  B1200	0000011     // 波特率1200
#define  B1800	0000012     // 波特率1800
#define  B2400	0000013     // 波特率2400
#define  B4800	0000014     // 波特率4800
#define  B9600	0000015     // 波特率9600
#define  B19200	0000016     // 波特率19200
#define  B38400	0000017     // 波特率38400
#define EXTA B19200         // 扩展波特率A
#define EXTB B38400         // 扩展波特率B
#define CSIZE	0000060     // 字符位宽度屏蔽码
#define   CS5	0000000     // 每字符5比特位
#define   CS6	0000020     // 每字符6比特位
#define   CS7	0000040     // 每字符7比特位
#define   CS8	0000060     // 每字符8比特位
#define CSTOPB	0000100     // 设置两个停止位 而不是1个
#define CREAD	0000200     // 允许接收
#define CPARENB	0000400     // 开启输出时产生奇偶位 输入时进行奇偶校验
#define CPARODD	0001000     // 输入/输入校验是奇校验
#define HUPCL	0002000     // 最后进程关闭后挂断
#define CLOCAL	0004000     // 忽略调制解调器（modem）控制线路
#define CIBAUD	03600000		/* input baud rate (not used) */    // 输入波特率（未使用）
#define CRTSCTS	020000000000		/* flow control */              // 流控制

#define PARENB CPARENB      // 开启输出时产生奇偶位 输入时进行奇偶校验
#define PARODD CPARODD      // 输入/输入校验是奇校验

/* c_lflag bits */      // termios 结构中本地模式标志字段c_lflag的符号常熟
#define ISIG	0000001     // 当收到字符INTR QUIT SUSP 或 DSUSP 产生相应的信号
#define ICANON	0000002     // 开启规范模式（熟模式）
#define XCASE	0000004     // 若设置了ICANON 则终端是大写字符的
#define ECHO	0000010     // 回显输入了字符
#define ECHOE	0000020     // 若设置了ICANON 在ERASE/WERASE 将擦除前一字符/单词
#define ECHOK	0000040     // 若设置了ICANON 则KILL字符将擦除当前行
#define ECHONL	0000100     // 如设置了ICANON 则即使ECHO没有开启也回显NL字符
#define NOFLSH	0000200     // 当生成SIGINT和SIGAUIT信号时不刷新输入输出队列 当生成SIGSUSP信号时， 刷新输入队列
#define TOSTOP	0000400     // 发送SIGITOU信号到后台进程的进程组 该后台进程视图写自己的控制终端
#define ECHOCTL	0001000     // 若设置了ECHO 则除TAB NL START 和 STOP 以外的ASCII 控制信号将被回显成
#define ECHOPRT	0002000     // 若设置了ICANON和IECHO 则字符在擦除时将显示
#define ECHOKE	0004000     // 若设置了ICANON 则KILL通过擦除行上的所有字符被回显
#define FLUSHO	0010000     // 输出被刷新 通过键入DISCARD字符 该标志被翻转
#define PENDIN	0040000     // 当下一个字符是读时，输入队列中的所有字符将被重显
#define IEXTEN	0100000     // 开启实现时定义的输入处理

/* modem lines */   // modem线路信号符号常数
#define TIOCM_LE	0x001   // 线路允许
#define TIOCM_DTR	0x002   // 数据终端就绪
#define TIOCM_RTS	0x004   // 请求发送
#define TIOCM_ST	0x008   // 串行数据发送
#define TIOCM_SR	0x010   // 串行数据接收
#define TIOCM_CTS	0x020   // 清除发送
#define TIOCM_CAR	0x040   // 载波监测
#define TIOCM_RNG	0x080   // 响铃指示
#define TIOCM_DSR	0x100   // 数据设备就绪
#define TIOCM_CD	TIOCM_CAR
#define TIOCM_RI	TIOCM_RNG

/* tcflow() and TCXONC use these */ // tcflow() 和 TCXONC 使用这些符号常数
#define	TCOOFF		0       // 挂起输出
#define	TCOON		1       // 重启被挂起的输出
#define	TCIOFF		2       // 系统传输一个STOP字符 使设备停止向系统传输数据
#define	TCION		3       // 系统传输一个start字符 使设备开始向系统传输数据

/* tcflush() and TCFLSH use these */    // tcflush（）和TCFLSH使用这些符号常数
#define	TCIFLUSH	0       //  清接受到的数据但不读
#define	TCOFLUSH	1       // 清已写的数据但不传送
#define	TCIOFLUSH	2       // 清接收到的数据但不读 清已写的数据但不传送

/* tcsetattr uses these */  // tcsetattr（）使用这些符号函数
#define	TCSANOW		0       // 改变立即发生
#define	TCSADRAIN	1       // 改变在所有已写的输出被传输之后发生
#define	TCSAFLUSH	2       // 改变在所有已写的输出被传输之后并且在所有接收到但还没有读取的数据被丢弃之后发生

typedef int speed_t;    // 波特率数值类型

extern speed_t cfgetispeed(struct termios *termios_p);  // 返回 termios_p所指termios结构中的接收波特率
extern speed_t cfgetospeed(struct termios *termios_p);  // 返回 termios_p所指termios结构中的发送波特率
extern int cfsetispeed(struct termios *termios_p, speed_t speed);   // 将 termios_p所指termios结构中的接收波特率设置为speed
extern int cfsetospeed(struct termios *termios_p, speed_t speed);   // 将 termios_p所指termios结构中的发送波特率设置为speed
extern int tcdrain(int fildes); // 等待fildes 所指对象已写输出数据被传送出去
extern int tcflow(int fildes, int action);  // 挂起/重启 fildes所指对象数据的接收和发送
extern int tcflush(int fildes, int queue_selector); // 丢弃fildes指定对象所有已写但还没传送以及所有已收到但还没有读取的数据
extern int tcgetattr(int fildes, struct termios *termios_p);    // 获取与句柄fileds对应对象的参数 并将其保存在 termios_p所指的地方
extern int tcsendbreak(int fildes, int duration);   // 如果终端使用一部串行数据传输 则在一定时间连续传输一系列0值比特位
extern int tcsetattr(int fildes, int optional_actions,  // 使用termios结构指针 termios_p所指的数据 设置与设置终端相关的参数
	struct termios *termios_p);

#endif
